#include "cp0_regdef.h"

	.data

kernel_stack:	.word	0
kernel_pc:	.word	0
#----------------------------------------------------------------------------
# Exception handler code
# 1/ Saves the context
# 2/ Executes the interrupt
# 2/ Loads the context and restart the process
# $k1 contains $at
#----------------------------------------------------------------------------
# saving the context
	.text
	.globl exception_handler
exception_handler:
	#we first check if there is a process to save
	lw $k0, running
	beq $k0, $0, past_save
	# do the saving 
	.set noat
	sw $k1, 0($k0)
	.set at
	sw $v0, 4($k0)
	sw $v1, 8($k0)
	sw $a0, 12($k0)
	sw $a1, 16($k0)
	sw $a2, 20($k0)
	sw $a3, 24($k0)
	sw $t0, 28($k0)
	sw $t1, 32($k0)
	sw $t2, 36($k0)
	sw $t3, 40($k0)
	sw $t4, 44($k0)
	sw $t5, 48($k0)
	sw $t6, 52($k0)
	sw $t7, 56($k0)
	sw $t8, 60($k0)
	sw $t9, 64($k0)
	sw $s0, 68($k0)
	sw $s1, 72($k0)
	sw $s2, 76($k0)
	sw $s3, 80($k0)
	sw $s4, 84($k0)
	sw $s5, 88($k0)
	sw $s6, 92($k0)
	sw $s7, 96($k0)
	sw $sp, 100($k0)
	sw $fp, 104($k0)
	sw $ra, 108($k0) 
	mfc0 $t0, epc
	sw $t0, 112($k0)
	sw $gp, 116($k0)
	j handler
past_save:
	# we need to save the stack and the pc of the kernel (because it was running)
	mfc0 $t0, epc
	sw $t0, kernel_pc($0)
	sw $sp, kernel_stack($0)
handler:
	# the cause register is saved and will be used by a C function that manages the interrupts
	mfc0 $t0, cause
	sw $t0, cause_reg($0)
	jal kexception
	
	#back from the C exception handler, we must restore the context of the running process (if any)
	lw $k0, running
	beq $k0,$0, past_load
	#restoring
	lw $t0, 112($k0)
	#addi $t0, $t0, 4
	mtc0 $t0, epc
	.set noat
	lw $at, 0($k0)
	.set at
	lw $v0, 4($k0)
	lw $v1, 8($k0)
	lw $a0, 12($k0)
	lw $a1, 16($k0)
	lw $a2, 20($k0)
	lw $a3, 24($k0)
	lw $t0, 28($k0)
	lw $t1, 32($k0)
	lw $t2, 36($k0)
	lw $t3, 40($k0)
	lw $t4, 44($k0)
	lw $t5, 48($k0)
	lw $t6, 52($k0)
	lw $t7, 56($k0)
	lw $t8, 60($k0)
	lw $t9, 64($k0)
	lw $s0, 68($k0)
	lw $s1, 72($k0)
	lw $s2, 76($k0)
	lw $s3, 80($k0)
	lw $s4, 84($k0)
	lw $s5, 88($k0)
	lw $s6, 92($k0)
	lw $s7, 96($k0)
	lw $sp, 100($k0)
	lw $fp, 104($k0)
	lw $ra, 108($k0)
	lw $gp, 116($k0)
	j end
past_load:
	# no process has been selected to run, we load the kernel pc and stack
	lw $sp, kernel_stack($0)
	lw $t0, kernel_pc($0)
	mtc0 $t0, epc
end:	
	# return from interrupt
	eret

